package database

import (
	"context"
	"crypto/md5"
	"fmt"
	"grpc.getaway.adminspro.padmins.com/pkg/config"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/db"
	"grpc.getaway.adminspro.padmins.com/pkg/support/log"
	"sync"
	"time"
)

type dbStruct struct {
	sync.RWMutex
	dbConnMap map[string]*db.DbConnect
}

func (d *dbStruct) GetDefaultDb(ctx context.Context) *db.Db {
	dsn := fmt.Sprintf(
		"%s:%s@tcp(%s:%d)/%s?charset=%s",
		config.Config.Db.Username,
		config.Config.Db.Password,
		config.Config.Db.Host,
		config.Config.Db.Port,
		config.Config.Db.Dbname,
		config.Config.Db.Charset,
	)
	return db.New(d.open(config.Config.Db.Driver, dsn)).SetContext(ctx).SetLogger(log.WithContext(ctx))
}

func (d *dbStruct) GetDb(driver, dsn string) *db.Db {
	return db.New(d.open(driver, dsn))
}

func (d *dbStruct) open(driver, dsn string) *db.DbConnect {
	d.Lock()
	defer d.Unlock()

	k := key(dsn)

	if _, ok := d.dbConnMap[k]; !ok {
		if d.dbConnMap == nil {
			d.dbConnMap = make(map[string]*db.DbConnect)
		}

		dbConnect := db.Open(driver, dsn)
		sqlDb := dbConnect.Connect()
		sqlDb.SetConnMaxLifetime(time.Duration(config.Config.Db.ConnMaxLifetime) * time.Second)
		sqlDb.SetMaxOpenConns(config.Config.Db.MaxOpenConns)
		sqlDb.SetMaxIdleConns(config.Config.Db.MaxIdleConns)
		d.dbConnMap[k] = dbConnect
	}

	return d.dbConnMap[k]
}

func key(dsn string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(dsn)))
}

var Db *dbStruct

func init() {
	Db = &dbStruct{}
}
